package plgwsmsg

import (
	"encoding/binary"
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/msgpack"
	"io"
)

const (
	errcode_invalid_param = 10
)

const (
	msgpack_type_str = 0x01
	msgpack_str_0xD5 = 0x05
	msgpack_str_0xD9 = 0xD9
	msgpack_str_0xDA = 0xDA
	msgpack_str_0xDB = 0xDB

	msgpack_type_bin = 0x02
	msgpack_bin_0xC4 = 0xC4
	msgpack_bin_0xC5 = 0xC5
	msgpack_bin_0xC6 = 0xC6
)

func WriteBinMsgPack(w io.Writer, head string, msg []byte) (int, error) {
	n, err := msgpack.WriteMsgPackStr(w, head)
	if err != nil {
		return n, err
	}

	n1, err1 := msgpack.WriteMsgPackBin(w, msg)
	if err1 != nil {
		return n1, err
	}
	return n1 + n, nil
}

func DecodeStrFromMsgPack(r io.Reader) (v string, err error) {
	cache := make([]byte, 1024)
	_, err = r.Read(cache[:1]) // type
	if err != nil {
		return
	}
	var size int
	typ := cache[0]
	if (typ >> 5) == msgpack_str_0xD5 {
		size = int(typ << 3 >> 3)
	} else if typ == msgpack_str_0xD9 {
		//str 8 stores a byte array whose length is upto (2^8)-1 bytes:
		//+--------+--------+========+
		//|  0xd9  |YYYYYYYY|  data  |
		//+--------+--------+========+
		_, err = r.Read(cache[:1]) // type
		if err != nil {
			return
		}
		size = int(cache[0])
	} else if typ == msgpack_str_0xDA {
		//str 16 stores a byte array whose length is upto (2^16)-1 bytes:
		//+--------+--------+--------+========+
		//|  0xda  |ZZZZZZZZ|ZZZZZZZZ|  data  |
		//+--------+--------+--------+========+
		_, err = r.Read(cache[:2]) // type
		if err != nil {
			return
		}
		size = int(binary.BigEndian.Uint16(cache[:2]))
	} else if typ == msgpack_str_0xDB {
		//str 32 stores a byte array whose length is upto (2^32)-1 bytes:
		//+--------+--------+--------+--------+--------+========+
		//|  0xdb  |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|  data  |
		//+--------+--------+--------+--------+--------+========+
		_, err = r.Read(cache[:4]) // type
		if err != nil {
			return
		}
		size = int(binary.BigEndian.Uint32(cache[:4]))
	} else {
		err = fmt.Errorf("非法的字符串类型:%X", typ)
		return
	}
	if size > len(cache) {
		cache = make([]byte, size)
	} else {
		cache = cache[:size]
	}
	n, err := io.ReadAtLeast(r, cache, size)
	return string(cache[:n]), err
}

func DecodeBytesFromMsgPack(r io.Reader) (v []byte, err error) {
	cache := make([]byte, 1024)
	_, err = r.Read(cache[:1]) // type
	if err != nil {
		return
	}
	var size int
	typ := cache[0]
	if typ == msgpack_bin_0xC4 {
		//str 8 stores a byte array whose length is upto (2^8)-1 bytes:
		//+--------+--------+========+
		//|  0xc4  |YYYYYYYY|  data  |
		//+--------+--------+========+
		_, err = r.Read(cache[:1]) // type
		if err != nil {
			return
		}
		size = int(cache[0])
	} else if typ == msgpack_bin_0xC5 {
		//str 16 stores a byte array whose length is upto (2^16)-1 bytes:
		//+--------+--------+--------+========+
		//|  0xc5  |ZZZZZZZZ|ZZZZZZZZ|  data  |
		//+--------+--------+--------+========+
		_, err = r.Read(cache[:2]) // type
		if err != nil {
			return
		}
		size = int(binary.BigEndian.Uint16(cache[:2]))
	} else if typ == msgpack_bin_0xC6 {
		//str 32 stores a byte array whose length is upto (2^32)-1 bytes:
		//+--------+--------+--------+--------+--------+========+
		//|  0xc6  |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA|  data  |
		//+--------+--------+--------+--------+--------+========+
		_, err = r.Read(cache[:4]) // type
		if err != nil {
			return
		}
		size = int(binary.BigEndian.Uint32(cache[:4]))
	} else {
		err = fmt.Errorf("非法的字符串类型:%X", typ)
		return
	}
	if size > len(cache) {
		cache = make([]byte, size)
	} else {
		cache = cache[:size]
	}
	n, err := io.ReadAtLeast(r, cache, size)
	return cache[:n], err
}

type BinMsgDecode struct {
	decodestep int8
	Head       string
	Body       []byte
	msgPackDec *msgpack.MsgPackDecode
}

func NewBinMsgDecode() *BinMsgDecode {
	rval := &BinMsgDecode{
		msgPackDec: msgpack.NewMsgPackDecode(),
	}
	return rval
}

func (this *BinMsgDecode) InputByte(v byte) int8 {
	if this.decodestep == -1 {
		this.decodestep = 0
		this.msgPackDec.Reset()
		this.msgPackDec.AssertType = msgpack_type_str
	}
	r := this.msgPackDec.InputByte(v)
	if r == -1 {
		this.decodestep = -1
		return r
	}
	if r == 1 {
		if this.decodestep == 0 {
			this.Head = string(this.msgPackDec.Bytes())
			this.decodestep = 1
			this.msgPackDec.AssertType = msgpack_type_bin
			return 0
		} else {
			this.Body = this.msgPackDec.Bytes()
			this.decodestep = -1
			return 1
		}
	}
	return 0
}

func (this *BinMsgDecode) InputBuf(buf []byte, onPack func(head string, body []byte)) int8 {
	for i := 0; i < len(buf); i++ {
		r := this.InputByte(buf[i])
		if r == -1 {
			return -1
		} else if r == 1 {
			onPack(this.Head, this.Body)
		}
	}
	return 0
}

func MakeCrcBuf(buf []byte) []byte {
	crc := gobase.CRC24QBuf(buf)
	crcBuf := make([]byte, 4)
	binary.BigEndian.PutUint32(crcBuf, crc)
	return append(buf, crcBuf...)
}

func CheckDecodeCrcBuf(buf []byte) ([]byte, error) {
	if len(buf) < 4 {
		return nil, fmt.Errorf("非法的数据包长度:%d", len(buf))
	}
	crc := gobase.CRC24QBuf(buf[:len(buf)-4])
	crc0 := binary.BigEndian.Uint32(buf[len(buf)-4:])
	if crc != crc0 {
		return nil, fmt.Errorf("非法的数据包, CRC校验失败:%d!=%d", crc, crc0)
	}
	return buf[:len(buf)-4], nil
}

func BuildBinMsgPack(cache *gobase.BytesBuilder, s string, body []byte) []byte {
	msgpack.WriteMsgPackStr(cache, s)
	msgpack.WriteMsgPackBin(cache, body)
	return cache.Bytes()
}
